package org.redis.cluster.admin.client.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.redis.cluster.admin.client.adapter.ClientConfigAdapter;
import org.redis.cluster.admin.client.factory.RedisClientFactory;
import org.redis.cluster.admin.client.model.RoutingClientConfig;
import org.redis.cluster.config.ClientConfig;
import org.redis.cluster.loadbalance.routing.RoutingManager;
import org.redis.cluster.loadbalance.slot.SlotClientConfig;
import org.redis.cluster.loadbalance.slot.SlotManager;
import org.redis.cluster.loadbalance.slot.SlotMapping;
import org.redis.cluster.transport.client.ClientManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import redis.clients.jedis.Jedis;

@Service
public class ClientService {
	
	protected final Logger logger=LoggerFactory.getLogger(getClass());

	@Autowired
	private SlotManager slotManager;
	@Autowired
	private RedisClientFactory redisClientFactory;
	@Autowired
	private RoutingManager routingManager;
	@Autowired
	private ClientManager clientManager;
	
	/**
	 * 返回客户端
	 * @return
	 */
	public Collection<RoutingClientConfig> getRoutingClients() {
		Collection<ClientConfig> clients=getClients();
		if(CollectionUtils.isEmpty(clients)) {
			return Collections.emptyList();
		}
		
		List<RoutingClientConfig> result=new ArrayList<RoutingClientConfig>();
		Map<ClientConfig,List<ClientConfig>> clientRouting=routingManager.getRouting();
		
		for(ClientConfig client:clients) {
			RoutingClientConfig routingClientConfig=ClientConfigAdapter.adaptRoutingClientConfig(client);
			
			List<ClientConfig> routings=clientRouting==null?null:clientRouting.get(client);
			if(routings==null) {
				routings=Collections.emptyList();
			}
			
			routingClientConfig.setRoutings(routings);
			result.add(routingClientConfig);
		}
		
		return result;
	}

	/**
	 * @return
	 */
	public Collection<ClientConfig> getClients() {
		return clientManager.getConfigs();
	}
	
	/**
	 * 返回客户端
	 * @param id
	 * @return
	 */
	public ClientConfig getClient(String id) {
		Collection<ClientConfig> configs=getClients();
		if(CollectionUtils.isEmpty(configs)) {
			return null;
		}
		
		for(ClientConfig config:configs) {
			if(!config.getId().equals(id)) {
				continue;
			}
			
			return config;
		}
		
		return null;
	}
	
	/**
	 * 注册
	 * @param config
	 * @return
	 */
	public boolean register(SlotClientConfig config) {
		if(config.getSlots().size()>slotManager.getSlotCount()) {
			return false;
		}
		
		return slotManager.registerSlotClient(config);
	}
	
	/**
	 * 取消注册
	 * @param sourceId
	 * @param targetId
	 * @return
	 */
	public boolean unregister(String sourceId,String targetId) {
		if(sourceId.equals(targetId)) {
			return false;
		}
		
		ClientConfig sourceConfig=getClient(sourceId);
		if(sourceConfig==null) {
			return false;
		}
		
		ClientConfig targetConfig=getClient(targetId);
		if(targetConfig==null) {
			return false;
		}
		
		SlotClientConfig sourceSlotClientConfig=ClientConfigAdapter.adaptClientConfig(sourceConfig);
		SlotClientConfig targetSlotClientConfig=ClientConfigAdapter.adaptClientConfig(targetConfig);
		return slotManager.unregisterSlotClient(sourceSlotClientConfig,targetSlotClientConfig);
	}
	
	/**
	 * 注册
	 * @param sourceId
	 * @param config
	 * @return
	 */
	public boolean registerRouting(String sourceId,ClientConfig config) {
		ClientConfig source=getClient(sourceId);
		if(source==null) {
			return false;
		}
		
		return routingManager.registerRouting(source, config);
	}
	
	/**
	 * 取消注册
	 * @param sourceId
	 * @param routingId
	 * @return
	 */
	public boolean unregisterRouting(String sourceId,String routingId) {
		ClientConfig source=getClient(sourceId);
		if(source==null) {
			return false;
		}
		
		ClientConfig routing=routingManager.getRouting(source,routingId);
		if(routing==null) {
			return false;
		}
		
		return routingManager.unregisterRouting(source, routing);
	}

	/**
	 * 返回mapping
	 * @param id
	 * @return
	 */
	public SlotMapping getSlotMapping(String id) {
		return slotManager.getSlotMapping(id);
	}
	
	/**
	 * 
	 * @param id
	 * @return
	 */
	public String getInfo(String id) {
		ClientConfig config=getClient(id);
		if(config==null) {
			return null;
		}
		
		return getInfo(config);
	}
	
	/**
	 * info
	 * @param config
	 * @return
	 */
	public String getInfo(ClientConfig config) {
		Jedis jedis=redisClientFactory.getClient(config);
		
		try {
			return jedis.info();
		}
		finally {
			try {
				redisClientFactory.returnClient(config, jedis);
			}
			catch(Exception e) {
				if(logger.isErrorEnabled()) {
					logger.error("",e);
				}
			}
		}
	}
}